#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"
#include "Channel.hpp"

// typedef std::function<void()> work_t;
using work_t = std::function<void()>;

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{
public:
    ProcessPool(int n, work_t w)
        :processnum(n),
         work(w)
    {}

    //channel:输出型参数
    //work_t work：回调函数
    int InitProcessPool()
    {
        //创建指定个数进程
        for(int i = 0; i < processnum; i++)
        {
            //先有管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if(n < 0) 
            {
                return PipeError;
            }

            //创建进程
            pid_t id = fork();
            if(id < 0)
            {
                return ForkError;
            }

            //建立通信信道
            if(id == 0)
            {
                //关闭历史fd
                //因为父进程每一轮循环都会打开一个写端，
                //从第二个子进程开始，每个子进程都会将父进程前面管理起来的写端和当前轮次打开的写端都继承下来
                //这导致除最后一个管道外的每个管道除了被父进程指向写端外，还会被其他子进程指向写端
                std::cout<< getpid() << ", child close history fd: "; //打印提示信息，方便检查是否存在问题
                for(auto &c : channels)
                {
                    std::cout<< c.wFd() << " ";
                    c.Close();
                }
                std::cout<< " over" <<std::endl;

                ::close(pipefd[1]); //关闭当前轮次打开的写端

                std::cout<< "debug: " << pipefd[0] <<std::endl;
                dup2(pipefd[0], 0); //重定向读端 让 0 号文件描述符指向管道读端
                work();

                ::exit(0);
            }

            //父进程执行
            ::close(pipefd[0]); //关闭读端
            channels.emplace_back(pipefd[1], id);
            //Channel ch(pipefd[1], id);
            //channels.push_back(ch);
        }

        return OK;
    }

    void DispatchTask()
    {
        int who = 0;
        
        //派发任务
        int num = 10;
        while(num--)
        {
            //选择一个任务
            int task =  tm.SelectTask();
            //选择一个子进程channel
            Channel &curr = channels[who++];
            who %= channels.size();
            
            std::cout<< "########################" << std::endl;
            std::cout<< "send "<< task << " to " << curr.Name() << ",任务还剩：" << num << std::endl;
            std::cout<< "########################" << std::endl;

            //派发任务
            curr.Send(task);

            sleep(1);
        }
    }

    void cleanProcessPool()
    {
        //version 3
        for(auto &c : channels)
        {
            c.Close(); //关闭写端，让读端的子进程退出
            pid_t rid = ::waitpid(c.Id(), nullptr, 0);
            if(rid > 0)
            {
                std::cout<< "child" << rid <<" wait ... success" << std::endl;
            }
        }

        //version 2
        // for(int i = channels.size() - 1; i >= 0; i--)
        // {
        //     channels[i].Close();
        //     pid_t rid = ::waitpid(channels[i].Id(), nullptr, 0);
        //     if(rid > 0)
        //     {
        //         std::cout<< "child" << rid <<" wait ... success" << std::endl;
        //     }
        // }

        //version 1
        // for(auto &c : channels)
        // {
        //     c.Close();
        // }

        // for(auto &c : channels)
        // {
        //     pid_t rid = ::waitpid(c.Id(), nullptr, 0);
        //     if(rid > 0)
        //     {
        //         std::cout<< "child" << rid <<" wait ... success" << std::endl;
        //     }
        // }
    }

    void DebugPrint()
    {
        for(auto &c : channels)
        {
            std::cout<< c.Name() <<std::endl;
        }
    }

private:
    std::vector<Channel> channels;
    int processnum; //进程数量
    work_t work; //任务
};
